#pragma warning(disable:4200)

#include "QWidgets.h"
#include "awtk.h"

enum {    
    Button_Width = 100,
    Button_Height = 20,

    Label_Width = 100,
    Label_Height = 20,

    QWidget_Width = 20,
    QWidget_Height = 20,
};


static QVector<QString> g_style_int;

//QWidget
IMPLEMENT_META(QWidget, QObject)

typedef struct _qwidget_t {
    widget_t widget;
    QWidget *qwidget;
}qwidget_t;

static widget_vtable_t s_widget_vtable;
static ret_t qwidget_on_paint_self(widget_t* widget, canvas_t* c)
{
    QWidget *w = ((qwidget_t*)widget)->qwidget;
    w->onPaint(c);    
    return RET_OK;
}

static ret_t qwidget_on_event(widget_t* widget, event_t* e)
{
    QWidget *w = ((qwidget_t*)widget)->qwidget;
    w->onEvent(e);    
    return RET_OK;
}

QWidget::QWidget(QWidget *parent)
    :QObject(parent)
{        
    m_wid = widget_create(parent? parent->wid() : NULL, &s_widget_vtable, 0, 0, QWidget_Width, QWidget_Width);
    qwidget_t *w = (qwidget_t*)m_wid;
    w->qwidget = this;
    m_canvas = NULL;
}

QWidget::QWidget(widget_t *wid, QWidget *parent)
    :QObject(parent)
{
    Q_ASSERT(wid && ((wid->parent == NULL && parent == NULL) || (wid->parent == parent->wid())));
    m_wid = wid;     
    m_canvas = NULL;
}

QWidget::QWidget(no_create_widget no, QWidget *parent)
    :QObject(parent)
{
    m_wid = NULL;
    m_canvas = NULL;
}

QWidget::~QWidget()
{
    if (m_wid)
    {
        widget_destroy(m_wid);
        m_wid = NULL;
    }
}

int QWidget::onPaint(canvas_t* c)
{
    QPaintEvent event;
    m_canvas = c;
    paintEvent(&event);
    m_canvas = NULL;
    return 0;
}

int QWidget::onEvent(event_t* e)
{
    uint16_t type = e->type;
    switch (type)
    {
    case EVT_POINTER_DOWN:
    case EVT_POINTER_UP:
    case EVT_POINTER_MOVE:
    {
        pointer_event_t* evt = (pointer_event_t*)e;
        QMouseEvent event;
        event.m_windowPos = QPoint(evt->x, evt->y);
        event.m_pos = mapFromGlobal(event.m_windowPos);
        if (evt->button)
            event.m_button = (Qt::LeftButton | Qt::RightButton);

        if (type == EVT_POINTER_DOWN)
            mousePressEvent(&event);
        else if (type == EVT_POINTER_UP)
            mouseReleaseEvent(&event);
        else
            mouseMoveEvent(&event);
        break;
    }
    default:
        break;
    }
    return 0;
}

canvas_t *QWidget::canvas()
{
    return m_canvas;
}

widget_t *QWidget::wid()
{
    return m_wid;
}

QWidget *QWidget::parentWidget()
{
    return (QWidget *)m_parent;
}

void QWidget::setParent(QWidget *parent)
{
    if (m_parent)
        widget_remove_child(parentWidget()->wid(), this->wid());
    QObject::setParent(parent);       
    widget_add_child(parent->wid(), m_wid);
}

QFont QWidget::font()
{
    return QFont();
}

void QWidget::setFont(const QFont &ft)
{

}

void QWidget::setEnabled(bool flag)
{
    widget_set_enable(m_wid, flag);
}

bool QWidget::isEnabled()
{
    value_t v;
    widget_get_prop(m_wid, WIDGET_PROP_ENABLE, &v);
    return (v.value.b != 0);
}

QPoint QWidget::mapToGlobal(QPoint pt)
{
    QWidget *w = this;
    while (w)
    {
        pt.rx() += w->x();
        pt.ry() += w->y();
        w = w->parentWidget();
    }
    return pt;
}

QPoint QWidget::mapFromGlobal(QPoint pt)
{
    QWidget *w = this;
    while (w)
    {
        pt.rx() -= w->x();
        pt.ry() -= w->y();
        w = w->parentWidget();
    }
    return pt;
}

void QWidget::setStyleSheet(const QString &styleSheet)
{    
    QStringList list = styleSheet.split(";");
    for (int i = 0; i < list.size(); i++)
    {
        QStringList kv = list[i].split("=");
        if (kv.size() == 2)
        {
            value_t v;
            value_set_str(&v,kv[1].c_str());
            widget_set_style(m_wid, kv[0].c_str(), &v);
        }
    }    
}

void QWidget::setLayout(QLayout *layout)
{
    Q_ASSERT(0);
}

void QWidget::move(int x, int y)
{
    widget_move(m_wid,x, y);
}

void QWidget::resize(int w, int h)
{
    widget_resize(m_wid, w, h);
}

void QWidget::resize(QSize size)
{
    resize(size.width(), size.height());
}

void QWidget::setFixedWidth(int w)
{
    widget_resize(m_wid, w, height());
}

void QWidget::setFixedHeight(int h)
{
    widget_resize(m_wid, width(), h);
}

void QWidget::setFixedSize(int w, int h)
{
    resize(w, h);
}

void QWidget::setFixedSize(QSize sz)
{
    setFixedSize(sz.width(),sz.height());
}

void QWidget::setMinimumWidth(int w)
{
    widget_resize(m_wid, w, height());
}

void QWidget::setMinimumHeight(int h)
{
    widget_resize(m_wid, width(), h);
}

void QWidget::setMinimumSize(int w, int h)
{
    widget_resize(m_wid, w, h);
}

void QWidget::setMinimumSize(QSize sz)
{
    setMinimumSize(sz.width(), sz.height());
}

void QWidget::setMaximumWidth(int width)
{

}

void QWidget::setMaximumHeight(int height)
{

}

void QWidget::setMaximumSize(int x, int y)
{

}

void QWidget::setMaximumSize(QSize sz)
{

}

QRect QWidget::geometry()
{
    return QRect(x(), y(), width(), height());
}

void QWidget::setGeometry(QRect rc)
{
    setGeometry(rc.x(), rc.y(), rc.width(), rc.height());
}

void QWidget::setGeometry(int x, int y, int w, int h)
{        
    widget_move_resize(m_wid,x,y,w,h);
}

QRect QWidget::rect()
{
    return QRect(0, 0, width(), height());
}

QSize QWidget::size()
{
    return QSize(width(), height());
}

int QWidget::x()
{
    return m_wid->x;
}

int QWidget::y()
{
    return m_wid->y;
}

int QWidget::width()
{
    return m_wid->w;
}

int QWidget::height()
{
    return m_wid->h;
}

void QWidget::setVisible(bool visible)
{
    widget_set_visible(m_wid, visible? 1:0);
}

void QWidget::show()
{
    widget_set_visible(m_wid, 1);
}

void QWidget::hide()
{
    widget_set_visible(m_wid, 0);
}

void QWidget::update()
{
    widget_invalidate(m_wid, NULL);
}

void QWidget::paintEvent(QPaintEvent *event)
{
}

void QWidget::mousePressEvent(QMouseEvent *event)
{
}

void QWidget::mouseReleaseEvent(QMouseEvent *event)
{
}

void QWidget::mouseMoveEvent(QMouseEvent *event)
{

}

void QWidget::dumpWidgetTree()
{   
    qDebug() << "QWidget Tree:";
    dump(this, 0);

    qDebug() << "Awtk Tree:";
    dump(m_wid, 0);
}

void QWidget::dump(QWidget *widget, int level)
{
    QString tab;
    for (int i = 0; i < level; i++)
        tab += "  ";

    qDebug() << tab << widget->meta()->className() << widget << widget->geometry();
    for (int i = 0; i < widget->m_childs.size(); i++)
    {        
        if (widget->m_childs[i]->inherits("QWidget"))
            dump((QWidget *)widget->m_childs[i], level + 1);
    }
}

void QWidget::dump(widget_t *wid, int level)
{
    QString tab;
    for (int i = 0; i < level; i++)
        tab += "  ";

    qDebug() << tab << wid->vt->type << wid << QRect(wid->x, wid->y, wid->w, wid->h);
    if (wid->children)
    {
        for (int i = 0; i < wid->children->size; i++)
        {
            widget_t *sub_wid = (widget_t *)wid->children->elms[i];
            dump(sub_wid, level + 1);
        }
    }
}

//Window
IMPLEMENT_META(Window,QWidget)
Window::Window()
    :QWidget(NULL)
{
    m_wid = window_create(NULL, 0, 0, 0, 0);
}

//QPushButton
IMPLEMENT_META(QAbstractButton, QWidget)
static ret_t on_button_clicket(void* ctx, event_t* e) {
    QAbstractButton *btn = (QAbstractButton*)ctx;
    btn->emit(SIG_Clicked,NULL);
    if (btn->group())
        btn->group()->emit(SIG_Clicked, btn);
    return RET_OK;
}

QAbstractButton::QAbstractButton(QWidget *parent)
    :QWidget(no_create_widget(), parent)
{        
    Q_ASSERT(!m_wid);
}        

QPushButton::~QPushButton()
{

}

QButtonGroup *QAbstractButton::group() const
{
    return m_buttonGroup;
}

void QAbstractButton::setCheckable(bool flag)
{

}

void QAbstractButton::setChecked(bool flag)
{

}

bool QAbstractButton::isChecked()
{
    return false;
}

void QAbstractButton::setText(QString text)
{
    widget_set_text_utf8(m_wid, text.c_str());
}

void QAbstractButton::setIcon(const QIcon &icon)
{
    widget_set_style_str(m_wid, "icon", icon.id().c_str());
    widget_set_style_int(m_wid, "icon_at", ICON_AT_LEFT);
}

void QAbstractButton::setIconSize(const QSize &icon_size)
{

}

//QPushButton
IMPLEMENT_META(QPushButton, QAbstractButton)
QPushButton::QPushButton(QWidget *parent)
    :QAbstractButton(parent)
{    
    m_wid = button_create(parent ? parent->wid() : NULL, 0, 0, Button_Width, Button_Height);
    widget_on(m_wid, EVT_CLICK, on_button_clicket, this);
}

QPushButton::QPushButton(const QString &text, QWidget *parent)
    :QAbstractButton(parent)
{   
	m_wid = button_create(parent ? parent->wid() : NULL, 0, 0, Button_Width, Button_Height);
    widget_on(m_wid, EVT_CLICK, on_button_clicket, this);
    setText(text);
}

//QSwitchButton
IMPLEMENT_META(QSwitchButton, QWidget)
QSwitchButton::QSwitchButton(QWidget *parent)
    :QWidget(no_create_widget(),parent)
{
    m_wid = switch_create(parent ? parent->wid() : NULL, 0, 0, Button_Width, Button_Height);
}


//QRadioButton
IMPLEMENT_META(QRadioButton, QAbstractButton)
QRadioButton::QRadioButton(QWidget *parent)
    :QAbstractButton(parent)
{    
    m_wid = check_button_create_radio(parent ? parent->wid() : NULL, 0, 0, Button_Width, Button_Height);
    widget_on(m_wid, EVT_CLICK, on_button_clicket, this);
}

QRadioButton::QRadioButton(const QString &text, QWidget *parent)
    : QAbstractButton(parent)
{
    m_wid = check_button_create_radio(parent ? parent->wid() : NULL, 0, 0, Button_Width, Button_Height);
    widget_on(m_wid, EVT_CLICK, on_button_clicket, this);
    setText(text);
}

//QButtonGroup
IMPLEMENT_META(QButtonGroup, QObject)
QButtonGroup::QButtonGroup(QObject *parent)
    :QObject(parent)
{
    
}

void QButtonGroup::addButton(QAbstractButton *button,int id)
{
    button->m_buttonGroup = this;
    m_buttons.push_back(button);
}

//QLabel
IMPLEMENT_META(QLabel, QWidget)
QLabel::QLabel(QString text, QWidget *parent)
    :QWidget(no_create_widget(), parent)
{   
	Q_ASSERT(!m_wid);
	m_wid = label_create(parent? parent->wid():NULL, 0, 0, Label_Width, Label_Height);
    widget_set_text_utf8(m_wid, text.c_str());
}

QLabel::QLabel(QWidget *parent)
    :QWidget(no_create_widget(), parent)
{
    Q_ASSERT(!m_wid);
    m_wid = label_create(parent? parent->wid():NULL, 0, 0, Label_Width, Label_Height);
    widget_set_style_int(m_wid, STYLE_ID_TEXT_ALIGN_H, ALIGN_H_LEFT);    
}

QLabel::~QLabel()
{

}

QString QLabel::text()
{
    char text[128];
    widget_get_text_utf8(m_wid, text, 128);
    return text;
}

void QLabel::setText(QString text)
{
    widget_set_text_utf8(m_wid,text.c_str());
}

void QLabel::setAlignment(int option)
{
    int align_v = ALIGN_V_NONE, align_h = ALIGN_H_NONE;
    QStyle::getAlign(option, align_v, align_h);
    if (align_v != ALIGN_V_NONE)
        widget_set_style_int(m_wid, STYLE_ID_TEXT_ALIGN_V, align_v);
    if (align_h != ALIGN_H_NONE)
        widget_set_style_int(m_wid, STYLE_ID_TEXT_ALIGN_H, align_h);
}

//QStackedWidget
IMPLEMENT_META(QStackedWidget, QWidget)
QStackedWidget::QStackedWidget(QWidget *parent)
    :QWidget(parent)
{
    m_currentIndex = -1;    
}

void QStackedWidget::addWidget(QWidget *widget)
{
    widget->setParent(this);
    widget->setGeometry(0, 0, width(), height());
    m_widgets.push_back(widget);
    if (m_widgets.size() == 1)
        m_currentIndex = 0;
    else
    {
        widget->hide();
        widget->setEnabled(false);        
    }
}

void QStackedWidget::setCurrentIndex(int index)
{
    m_currentIndex = index;
    for (int i = 0; i < m_widgets.size(); i++) {
        bool visible = (m_currentIndex == i);
        m_widgets[i]->setVisible(visible);
        m_widgets[i]->setEnabled(visible);
    }
}

int QStackedWidget::currentIndex()
{
    return m_currentIndex;
}

//QListWidgetItem
QListWidgetItem::QListWidgetItem()
{

}

//QListWidget
IMPLEMENT_META(QListWidget, QWidget)
QListWidget::QListWidget(QWidget *parent)
    :QWidget(no_create_widget(), parent)
{    
    m_wid = list_view_create(parent? parent->wid():NULL, 0, 0, 0, 0);       
    widget_t *scroll_view = scroll_view_create(m_wid, 0, 0, 0, 0);    
    m_view = new QWidget(scroll_view, this);

    widget_t *scroll_bar = scroll_bar_create_desktop(m_wid, 0, 0, 0, 0);    
    scroll_view_set_yslidable(scroll_view, TRUE);

    widget_set_self_layout(scroll_view, "default(x=0, y=0,w=-12, h=100%)");
    widget_set_self_layout(scroll_bar, "default(x=right, y=0,w=12, h=100%)");
}

QListWidget::~QListWidget()
{
    for (int i = 0; i < m_items.size(); i++)
        delete m_items[i];
    m_items.clear();
}

void QListWidget::addItem(const QString &label)
{
    QListWidgetItem *item = new QListWidgetItem();
}

void QListWidget::addItem(QListWidgetItem *item)
{
    Q_ASSERT(0);
}

QListWidgetItem *QListWidget::takeItem(int row)
{
    Q_ASSERT(0);
    return NULL;
}

void QListWidget::setItemWidget(QListWidgetItem *item, QWidget *widget)
{
    Q_ASSERT(0);
}

int QListWidget::count()
{
    return m_items.size();
}

void QListWidget::addItemWidget(QWidget *widget)
{    
    int h = 0;
    for (int i = 0; i < m_items.size(); i++)
        h += m_items[i]->widget->height();

    QListWidgetItem *item = new QListWidgetItem();    
    item->widget = widget;    
    item->widget->move(0, h);    
    item->widget->setParent(m_view);
    m_items.push_back(item);
}

//QScrollArea
IMPLEMENT_META(QScrollArea, QWidget)
QScrollArea::QScrollArea(QWidget *parent)
    :QWidget(no_create_widget(), parent)
{
    m_wid = list_view_create(parent ? parent->wid() : NULL, 0, 0, 0, 0);
    widget_t *scroll_view = scroll_view_create(m_wid, 0, 0, 0, 0);
    m_scrollView = new QWidget(scroll_view, this);
    m_viewport = NULL;

    widget_t *scroll_bar = scroll_bar_create_desktop(m_wid, 0, 0, 0, 0);
    scroll_view_set_yslidable(scroll_view, TRUE);

    widget_set_self_layout(scroll_view, "default(x=0, y=0,w=-12, h=100%)");
    widget_set_self_layout(scroll_bar, "default(x=right, y=0,w=12, h=100%)");
}

QScrollArea::~QScrollArea()
{

}

void QScrollArea::setWidget(QWidget *widget)
{
    m_viewport = widget;
    m_viewport->setParent(m_scrollView);
}

void QScrollArea::setWidgetResizable(bool flag)
{

}

//QLayoutItem
QLayoutItem::QLayoutItem()
{
    row = 0;
    col = 0;
    align = 0;
}

//QLayout
QLayout::QLayout(QWidget *parent)
{
    Q_ASSERT(parent);
    m_widget = parent;
    m_left = 0;
    m_top = 0;
    m_right = 0;
    m_bottom = 0;
    m_spacing = 0;
}

QLayout::~QLayout()
{

}

void QLayout::addLayoutItem(const QLayoutItem &item)
{
    item.widget->setParent(m_widget);
    m_items.push_back(item);
}

void QLayout::update()
{
    Q_ASSERT(m_widget);
    doLayout();
}

void QLayout::setContentsMargins(int left, int top, int right, int bottom)
{
    m_left = left;
    m_top = top;
    m_right = right;
    m_bottom = bottom;
}

void QLayout::setMargin(int size)
{
    setContentsMargins(size, size, size, size);
}

void QLayout::setSpacing(int space)
{
    m_spacing = space;
}

//QBoxLayout
QBoxLayout::QBoxLayout(QWidget *parent)
    :QLayout(parent)
{    
}

void QBoxLayout::addWidget(QWidget *widget, int stretch , int align)
{
    QLayoutItem item;
    item.widget = widget;
    item.align = align;
    addLayoutItem(item);
}

//QHBoxLayout
QHBoxLayout::QHBoxLayout(QWidget *parent)
    :QBoxLayout(parent)
{

}

void QHBoxLayout::doLayout()
{
    widget_set_children_layout(m_widget->wid(), "default(r=1,c=0)");
}

//QVBoxLayout
QVBoxLayout::QVBoxLayout(QWidget *parent)
    :QBoxLayout(parent)
{

}

void QVBoxLayout::doLayout()
{
    widget_set_children_layout(m_widget->wid(), "default(r=0,c=1)");
}

//QGridLayout
QGridLayout::QGridLayout(QWidget *parent)
    :QBoxLayout(parent)
{

}

void QGridLayout::addWidget(QWidget *widget, int row, int column, int align)
{
    QLayoutItem item;
    item.widget = widget;
    item.align = align;
    item.row = row;
    item.col = column;
    addLayoutItem(item);
}

void QGridLayout::doLayout()
{
    int col = 0;
    int row = 0;
    for (int i = 0; i < m_items.size(); i++)
    {
        col = qMax(col, m_items[i].col + 1);
        row = qMax(row, m_items[i].row + 1);
    }

    QString layout = QString().sprintf("default(r=%d,c=%d,s=%d)", row,col,m_spacing);
    widget_set_children_layout(m_widget->wid(), layout.c_str());
}

//widget_init
void widget_init()
{
    memset(&s_widget_vtable,0,sizeof(s_widget_vtable));
    s_widget_vtable.type = WIDGET_TYPE_NONE;
    s_widget_vtable.size = sizeof(qwidget_t);
    s_widget_vtable.on_paint_self = qwidget_on_paint_self;
    s_widget_vtable.on_event = qwidget_on_event;

    g_style_int.push_back("bg_image_draw_type");
    g_style_int.push_back("font_size");
    g_style_int.push_back("text_align_v");
    g_style_int.push_back("text_align_h");
}